from proxy import ProxyServer, SecureProxyServer
from Pyro.errors import NamingError 
from crowd import Crowd
from paths import PathManager
import Pyro.core, Pyro.naming, connvalidator, getpass
import os, time, events, config, subprocess, shutil, time, const


def main():
    crowd = Crowd()
    path_manager = PathManager()
    blender_ip = config.BLENDER_IP
    #blender_port = config.BLENDER_PORT    
    inp = raw_input("Type remote Blender's ip [default=" + config.BLENDER_IP + "]: ")        
    if inp:
        blender_ip = inp
    
    Pyro.config.PYRO_NS_HOSTNAME = blender_ip 
    Pyro.core.initClient()
    locator = Pyro.naming.NameServerLocator()
    ns = locator.getNS(host=blender_ip, port=config.REMOTE_NAMESERVER_PORT)
    #change pyro config in order to point to the right nameserver hostname (the blender...)
    
    print 'finding remote objects...'
    try:
        URI = ns.resolve('Blender')
        print "Blender's URI: ", URI
    except NamingError,x:
        print 'Couldn\'t find object, nameserver says: ',x
    # creates a proxy for the Pyro object, and return that
    blender  = Pyro.core.getProxyForURI(URI)
    validator = connvalidator.UserLoginConnValidator()
    blender._setNewConnectionValidator(validator)
    
    ###########LOGIN#####################
    print "\n----------LOG INTO REMOTE BLENDER-----------"
    login = raw_input("Enter user name: ")
    password = getpass.getpass("Enter password: ")    
    blender._setIdentification((login, password))
    members = blender.login(config.SECURE_PROXY_PORT, None)
    
    if members != None:
        crowd.update_member_list(members)
        print "\nLogin success! \n"
        pub_ip = blender.get_public_ip()
        print "The blender says our public ip is: " + pub_ip
        print "Check that ports " + str(config.PYRO_LOCAL_PORT) + "," + str(config.NAMESERVER_LOCAL_PORT) + " are open and forwarded if you're behind a firewall!"
        
        if pub_ip:
            Pyro.config.PYRO_PUBLISHHOST = pub_ip
            Pyro.config.PYRO_PORT = config.PYRO_LOCAL_PORT
            Pyro.config.PYRO_NS_PORT = config.NAMESERVER_LOCAL_PORT
            
        event_listener = events.EventListener(blender, crowd, path_manager)
        event_listener.listener.crowd = crowd
        event_listener.start()
        print "Event listener activated"
        proxy_server = ProxyServer(config.PROXY_PORT, blender, crowd, path_manager)
        
        cert_file = config.CERTIFICATE_FOLDER + os.sep + config.CERTIFICATE_FILE
        if not os.path.exists(cert_file) and config.SSL_CONNECTION:
            print "\nYou must first generate an RSA Certificate file called " + config.CERTIFICATE_FILE + " and copy it into : " + cert_file  
            print "You can create a suitable certificate file, using Openssl, by running a command like this:\n"            
            print "\n  openssl req -newkey rsa:%s -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem \n" % config.RSA_PK_LENGTH
            print "The program will try to create a certificate file for you, please fill in the informations requested."
            raw_input('\nPress enter to begin creation...')
            create_certfile(cert_file)
        if os.path.exists(cert_file):
            secure_proxy_server = SecureProxyServer(config.SECURE_PROXY_PORT, blender, crowd, path_manager, cert_file )
            
            print "Starting ProxyServer server"
            proxy_server.start()
            i = 0
            while 1:
                if proxy_server.isAlive():
                    break 
                if i < const.MAX_SERVICE_STARTUP:
                    i = i+1
                    time.sleep(1)
                else:
                    print "Cannot start ProxyServer...exit"
                
            print "Starting Secure ProxyServer server"
            secure_proxy_server.start()
            show_menu(blender, event_listener, crowd, path_manager, proxy_server, secure_proxy_server)
        else:
            print "No valid certificate file found in %s \n" % cert_file 
            
    else:
        print "\nLogin failed!\nThe request to join the crowd was rejected by the blender..."
        exit()
        
def create_certfile(cert_file):
    openssl = "openssl req -newkey rsa:%s -new -x509 -days 365 -nodes -out cert.pem -keyout cert.pem" % config.RSA_PK_LENGTH   
    process = subprocess.Popen(openssl, shell=True, stdout=subprocess.PIPE)
    process.wait()
    if process.returncode == 0:
        print "Certificate created successfully!"
    else:
        print "Error creating certificate: try to build one by yourself!"
    raw_input('\nPress enter to continue...')
    shutil.move(config.CERTIFICATE_FILE, cert_file)
    
def wait_startup():
    pass

def serve_browser(proxy_server):
    if proxy_server:    
        proxy_server.start()
    else:
        print "Proxy server is not initialized!"
    
def show_menu(blender, event_listener, crowd, path_manager, proxy_server, secure_proxy_server):
    while 1:
        cls()
        print "---------------JONDO------------------"
        print "Choose an option:"
        print "1 - Show current built paths"
        print "2 - Show crowd nodes"
        print "q - quit application"
        print "--------------------------------------"
        inp = raw_input('>>: ')
        print "\n"
        if inp == '1':
            print "------------CURRENT PATHS-------------"
            path_manager.show_paths()
            print "--------------------------------------"
            raw_input("\nPress enter to continue...")
        elif inp == '2':
            print "----------AVAILABLE JONDOS------------"
            for jondo in crowd.get_jondos():
                print jondo.host_port
            print "--------------------------------------"
            raw_input("\nPress enter to continue...")
        elif inp == 'q':
            if raw_input("\nReally exit? [y/n]: ") == 'y':
                try:
                    if blender:
                        blender.logout()
                    print "Bye!"
                    quit()
                except: pass
        else:
            print "Please choose one available option!"
        time.sleep(2)

def cls():
    os.system(['clear','cls'][os.name == 'nt'])
            
if __name__ == '__main__':
    main()

